#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
#include "framebuffer.h"
#include <pthread.h>
#include "game.h"

#define BUFFSIZE 1024

//历史最高记录读取文件名
#define FILENAME "/home/ll/log"

int Els[ROW][LINE] = {0};	//棋盘数组
int row_ = 0;				//方块在棋盘中的行
int line_ = 0;				//方块在棋盘中的列

int colour_[ROW][LINE] = {0};	//每个方块对应的颜色
int colour = 0;					//当前方块的颜色
int colour_next = 0;			//下一个方块的颜色

int base = 0;		//当前方块类型
int base_next = 0;	//下一个方块类型
int spinsta = 0;	//方块的4种变化

int grade = 0;	//成绩
int level = 1;	//等级
int stop_ = 1;	//当前方块能否继续下落
int over = 0;	//判断当前游戏是否结束
int FLAG = -1;	//触摸区域对应的操作
pthread_t id = 0;	//线程id

/* 根据触摸区域获取相应的操作 */
static int Get_Handle(int x, int y)
{	
	if (x >= 525 && x <= 645 \
		&& y >= 348 && y <= 460)
	{
		return CHANGE;
	}
	else if (x >= 623 && x <= 713 \
		&& y >= 215 && y <= 348)
	{
		return MOVE_LEFT;
	}
	else if (x >= 623 && x <= 713 \
		&& y >= 5 && y <= 115)
	{
		return MOVE_RIGHT;
	}
	else if (x >= 630 && x <= 790 \
		&& y >= 137 && y <= 200)
	{
		return MOVE_DOWN;
	}
	else if (x >= 385 && x <= 511 \
		&& y >= 1 && y <= 127)
	{
		return PAUSE;
	}
	return -1;
}

/* 不断获取触摸坐标 */
static void *Touch(void *args)
{
	struct point p;
	
	while (stop_)
	{
		p = clickTouch();
		FLAG = Get_Handle(p.x, p.y);
	}
	pthread_exit((void *)0);
}

void Game_start()	//游戏开始主函数
{
	initEquipment();
	struct point p;
	Init_blocks();
	pthread_create(&id, NULL, Touch, NULL);
	while (1)
	{
		lcdDisplayPictures("/home/ll/ols/12.bmp", 0, 0);
		p = clickTouch();
		stop_ = 1;
		if (p.x >= 181 && p.x <= 608 \
			&& p.y >= 234 && p.y <= 305)
		{
			Init_data();
			Interface();

			srand((unsigned)time(NULL));
			 base = rand() % 7;
			colour = rand() % 5;
			while(Run());
			over = 1;
		}
		else if (p.x >= 280 && p.x <= 510 \
			&& p.y >= 358 && p.y <= 438)
		{
			setBackground(0xffffff);
			break;
		}
	}
	closeEquipment();
}

/* 初始化数据 */
void Init_data()
{
	int i, j;
	for (i = 0; i < ROW; i++)
	{
		for (j = 0; j < LINE; j++)
		{
			Els[i][j] = 0;		
			colour_[i][j] = 0;
		}
	}
	row_ = 0;
	line_ = 0;
	colour = 0;
	colour_next = 0;
	grade = 0;
	level = 1;
	over = 0;
}

/* 界面打印 */
void Interface()
{
	int x, y, k;
	int i, j;
	setBackground(0xffffff);

	for (x = 17; x < 511; x++)
	{
		for (i = 465; i < 471; i++)
		{
			lcdDrawPoint(x, i, 0xff0000);
		}
		for (y = 137; y < 143; y++)
		{
			lcdDrawPoint(x, y, 0xff0000);
		}
	}

	for (y = 143; y < 465; y++)
	{
		for (x = 17; x < 23; x++)
		{
			lcdDrawPoint(x, y, 0xff0000);
		}
		for (j = 505; j < 511; j++)
		{
			lcdDrawPoint(j, y, 0xff0000);
		}
	}
	
	for (y = 145; y < 465; y += 32)
	{
		for (x = 25; x < 505; x += 32)
		{
			lcdDrawRectangle(x, y, 30, 30, 0xc2c2c2);
		}
	}
	lcdDisplayPictures("/home/ll/ols/10.bmp", 385, 1);
	lcdDisplayPictures("/home/ll/ols/11.bmp", 515, 0);
	lcdDisplayPictures("/home/ll/ols/14.bmp", 185, 1);
	lcdDisplayPictures("/home/ll/ols/15.bmp", 281, 1);


	//初始化棋盘边界
	for (i = 0,k = ROW-2; i < 2 && k < ROW; i++,k++)
	{
		for (j = 0;	j < LINE; j++)
		{
			Els[i][j] = 2;
			Els[k][j] = 2;
		}
	}
	
	for (i = 2; i < ROW-2; i++)
	{
		for (j = 0,k = LINE-2; j < 2 && k < LINE; j++,k++)
		{
			Els[i][j] = 2;
			Els[i][k] = 2;
		}
	}
	Grade_print(grade);
}

int Init_blocks()	//初始化方块,共28种
{
	int i, j;
	int temp[DIA][DIA] = {0};
	int base_, spinsta_;

	for (i = 0; i < 2; i++)
	{
		//田
		blocks[0][0].space[1][i+1] = 1;
		blocks[0][0].space[2][i+1] = 1;
		//Z
		blocks[1][0].space[1][i] = 1;
		blocks[1][0].space[2][i+1] = 1;
		//反Z
		blocks[2][0].space[1][i+1] = 1;	
		blocks[2][0].space[2][i] = 1;	
	}
	for (i = 1;i < 4; i++)
	{
		//7
		blocks[3][0].space[1][0] = 1;	
		blocks[3][0].space[i][1] = 1;	
		//反7
		blocks[4][0].space[1][2] = 1;	
		blocks[4][0].space[i][1] = 1;	
	}
	for (i = 0; i < 4; i++)
	{
		//|
		blocks[5][0].space[i][1] = 1;	
	}
	for (i = 0; i < 3; i++)
	{
		//土
		blocks[6][0].space[1][1] = 1;	
		blocks[6][0].space[2][i] = 1;	
	}

	//根据7种基本形态衍生的其他方块
	for (base_ = 0; base_ < 7; base_++)
	{
		for (spinsta_ = 0; spinsta_ < 3; spinsta_++)
		{
			for (i = 0; i < DIA; i++)
			{
				for (j = 0;j < DIA; j++)
				{
					temp[i][j] = blocks[base_][spinsta_].space[i][j];
				}
			}

			for (i = 0; i < DIA; i++)
			{
				for (j = 0; j < DIA; j++)
				{
					blocks[base_][spinsta_+1].space[i][j] = temp[4-1-j][i];
				}
			}
		}

	}
	return 0;
}

void Next_blocks()	//下一个方块的打印
{
	int i, j;
	int x, y;

	for (j = 0, y = (129-32); y >= 1; j++, y -= 32)
	{
		for (i = 0, x = 25; x < 126; i++, x += 32)
		{	
			if (blocks[base_next][0].space[i][j] == 1)
			{
				Select_colour(&colour_next);	
				lcdDrawRectangle(x, y, 30, 30, colour_next);
				continue;
			}
			lcdDrawRectangle(x, y, 30, 30, 0xc2c2c2);
		}
	}

}

int Read_record()	//从文件中读取最高记录
{
	FILE *fps = NULL;
	FILE *fpd = NULL;
	char buff[BUFFSIZE] = {0};
	int n = 0;

	fps = fopen(FILENAME,"r+");
	if (fps == NULL)
	{
		perror("fopen()");
		exit(1);
	}
	

	fgets(buff,BUFFSIZE,fps);
	n = atoi(buff);
	
	if (grade > n)
	{
		fpd = fopen(FILENAME,"w+");
		if (fpd == NULL)
		{
			perror("fopen()");
			exit(1);
		}

		fprintf(fpd,"%d",grade);
		fclose(fpd);
	}
	fclose(fps);
	return n;
}

/* 根据分数打印相应图片 */
static void get_score(int number, int temp)
{
	int i, x, y;
	int buf[4] = {0};
	char Name[126] = {0};
	int k = 0;
	
	if (number < 10000)
	{
		do
		{
			buf[k++] = number % 10;
			number /= 10;
		} while (number);
	}

	if (grade > 0 && grade % 100 == 0)	//每一100分等级加一
	{
		level++;
	}
	
	if (temp == 1)
	{
		for (i = 0, x = 217, y = 1; i < 4; i++, y += 32)
		{
			sprintf(Name,"%s%d.bmp","/home/ll/ols/",buf[i]);
			lcdDisplayPictures(Name, x, y);
		}
	}
	else if (temp == 0)
	{
		for (i = 0, x = 313, y = 1; i < 4; i++, y += 32)
		{
			sprintf(Name,"%s%d.bmp","/home/ll/ols/",buf[i]);
			lcdDisplayPictures(Name, x, y);
		}
	}
}

void Grade_print(int grade)		//打印成绩
{
	get_score(grade, 0);
	get_score(Read_record(), 1);
}

void Select_colour(int *select)	//颜色选择函数
{
	switch (*select)
	{							
		case 0:
		{
			*select = 0xff0000;
			break;
		}
		case 1:
		{
			*select = 0xff00;
			break;
		}
		case 2:
		{
			*select = 0xff;
			break;
		}
		case 3:
		{
			*select = 0xa020f0;
			break;
		}
		case 4:
		{
			*select = 0xff34b3;
			break;
		}
	}

}

void Ols_load()	//方块赋值给棋盘
{
	int i, j;

	for (i = 0; i < DIA; i++)
	{
		for (j = 0;j < DIA; j++)		
		{
			if (Els[i+row_][line_+j] != 2)	//防止覆盖已经下落完成的方块
				Els[i+row_][line_+j] = blocks[base][spinsta].space[i][j];
		}
	}
	trave_();
}

void trave_()	//根据棋盘数值打印相对应的颜色
{
	int i, j;
	int x, y;
	int colour_cur = 0;

	for (j = 2, y = (465-32); y >= 145; j++, y -= 32)
	{
		for (i = 2, x = 25; x < 505; i++, x += 32)
		{
			if (Els[i][j] == 1)	//表示正在下落的方块
			{
				Select_colour(&colour);
				lcdDrawRectangle(x, y, 30, 30, colour);
			}
			else if(Els[i][j] == 2)	//已经下落完成的方块
			{
				Select_colour(&colour_[i][j]);
				lcdDrawRectangle(x, y, 30, 30, colour_[i][j]);
			}
			else
				lcdDrawRectangle(x, y, 30, 30, 0xc2c2c2);
		}
	}

}



static void alrmAction(int s, siginfo_t *infop, void *unused)	//信号控制函数,内为下落函数
{
	if (over || (stop_ == 0) || (infop->si_code != SI_KERNEL))
		return ;

	if (Judge_move(MOVE_DOWN) == 1)
		Exec_command(MOVE_DOWN);
	else
	{	
		stop_ = 0;
	}
}

int Set_time()	//根据等级设置下落速度并用信号控制并发
{
	struct sigaction sa;

	sa.sa_sigaction = alrmAction;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_SIGINFO;

	sigaction(SIGALRM, &sa, NULL);
	if (level == 1)
	{
		struct itimerval new = {{0,800000},{0,800000}};
		setitimer(ITIMER_REAL,&new,NULL);
	}
	else if (level == 2)
	{
		struct itimerval new = {{0,600000},{0,600000}};
		setitimer(ITIMER_REAL,&new,NULL);
	}
	else if (level >= 3)
	{
		struct itimerval new = {{0,500000},{0,500000}};
		setitimer(ITIMER_REAL,&new,NULL);
	}
	FLAG = -1;
	while(stop_)
	{
		if (FLAG < 0)
			continue;
		switch(FLAG)
		{
			//退出
			case PAUSE:
					Game_pause();
					break;
			case CHANGE:	//变形
					if (Judge_chage() == 1)
						Exec_command(CHANGE);
					break;
			case MOVE_LEFT: //左移
					if (Judge_move(MOVE_LEFT) == 1)
						Exec_command(MOVE_LEFT);
					break;
			case MOVE_RIGHT://右移
					if (Judge_move(MOVE_RIGHT) == 1)
						Exec_command(MOVE_RIGHT);
					break;
			case MOVE_DOWN:	//加速下落
					if (Judge_move(MOVE_DOWN) == 1)
					{
						Exec_command(MOVE_DOWN);
					}
					else
					{	
						Judge_dis();
						return 1;
					}
			default :
					break;
		}
		FLAG = -1;			
	}
	Judge_dis();
	return 1;
}

void Game_pause()	//游戏暂停
{
	struct itimerval pause_ = {0}, old;

	setitimer(ITIMER_REAL,&pause_,&old);
	lcdDisplayPictures("/home/ll/ols/13.bmp", 385, 1);
	FLAG = -1;	
	while(1)
	{
		if (FLAG == PAUSE)
			break;
	}
	Interface();
	Next_blocks();
	setitimer(ITIMER_REAL,&old,NULL);
}

int Run()	//运行函数
{
	//初始化方块下落位置
	int ret = 0;
	spinsta = 0;
	row_ = 2;
	line_ = 6;
	stop_ = 1;
		
	//给下一个方块确定类型和颜色
	srand((unsigned)time(NULL));
	base_next = rand() % 7;
	colour_next = rand() % 5;

	Next_blocks();
	//判断游戏是否结束

	if (Judge_over() == 0)
	{
		return 0;
	}
	
	Ols_load();
	//根据等级匹配下落速度
	
	ret = Set_time();	

	base = base_next;	
	colour = colour_next;
	return ret;
}

//游戏结束判断
int Judge_over()
{
	int i, j;
	//最上一格存在方块
	for (j = 2; j < LINE-2; j++)
	{
		if (Els[2][j] == 2)
		{
			return 0;
		}
	}
	//下一个方块不能进入棋盘
	for (i = 0; i < DIA; i++)
	{
		for (j = 0; j < DIA; j++)
		{
			if (blocks[base][spinsta].space[i][j] == 1)
			{
				if (Els[row_+i][line_+j] == 2)
				{
					return 0;
				}
			}
		}
	}
	return 1;
}

//判断方块能否移动
int Judge_move(int move)
{

	int i, j;
	int f_row,f_line;

	switch(move)
	{
		case 1:					//left
				f_row = 0;
				f_line = -1;		
				break;
		case 2:					//right
				f_row = 0;
				f_line = 1;		
				break;

		case 3:					//down
				f_row = 1;
				f_line = 0;		
				break;

	}

	for (i = 0; i < DIA; i++)
	{
		for (j = 0; j < DIA; j++)
		{
			if (Els[row_+i][line_+j] == 1)
			{
				if (Els[row_+i+f_row][line_+j+f_line] == 2)	
				{
					return 0;
				}
			}
		}
	}
	return 1;
}
//判断方块是否能旋转
int Judge_chage()
{
	int i, j;
	int count = 0;

	if (spinsta+1 > 3)
		spinsta = -1;

	for (i = 0; i < DIA; i++)
	{
		for (j = 0; j < DIA; j++)
		{
			if (blocks[base][spinsta+1].space[i][j] == 1)
			{
				if (Els[row_+i][line_+j] != 2)
				{
					count++;
					if (count == 4)
					{
						return 1;
					}
				}
			}	
		}
	}
	return 0;	
}

void Judge_dis()
{
	int i, j;
	int count = 0;
	int temp = 0;
	int flag = 0;
	int n = 0;
	int score = 0;
//下落完成的方块记录颜色并赋值为2
	for (i = 2; i < ROW-2; i++)
	{
		for (j = 2; j < LINE-2; j++)
		{
			if (Els[i][j] == 1)
			{
				Els[i][j] = 2;
				colour_[i][j] = colour;
			}
		}
	}
//判断是否能消行
	for (i = ROW-3; i >= 2; i--)
	{
		count = 0;	
		flag = 0;
		for (j = 2; j < LINE-2; j++)
		{
			if (Els[i][j] == 2)
			{
				count++;
			}
		}
		if (count == 10)
		{
			temp = i;
			Exec_dis(temp);
			n++;
			grade += 10;
			i = temp+1;	//i从原来位置重新判断
			flag = 1;
		}
		if (flag)
			score += n*10;
	}
	if (n >= 2)
		grade += score;
	Grade_print(grade);
	trave_();
}
//执行命令
void Exec_command(int command)
{
	switch(command)
	{
		case 0:			//旋转
				spinsta++;
				Dis_last(command);
				break;
		case 1:			//左移
				line_--;
				Dis_last(command);
				break;
		case 2:			//右移
				line_++;
				Dis_last(command);
				break;
		case 3:			//下落
				row_++;
				Dis_last(command);
	}
}

//执行消行
void Exec_dis(int row)
{
	int i, j;

	for (j = 2;j < LINE-2; j++)
	{
		Els[row][j] = 0;
	}

	for (i = row; i > 2; i--)
	{
		for (j = 2; j < LINE-2; j++)
		{
			Els[i][j] = 0;
			Els[i][j] = Els[i-1][j];
		}
	}
}

void Dis_last(int flag)	//消除上个状态
{
	int i, j;
	int last_row, last_line;
	//变形
	if (flag == 0)
	{
		last_row = 0;
		last_line = 0;
	}
	//左移
	else if(flag == 1)
	{
		last_row = 0;
		last_line = 1;
	}
	//右移
	else if(flag == 2)
	{
		last_row = 0;
		last_line = -1;
	}
	//下移
	else
	{
		last_row = -1;
		last_line = 0;
	}

	for (i = 0; i < DIA; i++)
	{
		for (j = 0; j < DIA; j++)
		{
			if (Els[i+row_+last_row][line_+j+last_line] != 2)
				Els[i+row_+last_row][line_+j+last_line] = 0;
		}
	}
	Ols_load();
}

